/*
 *--------------------------------------------------------------------------
 *   Battlefield - A Realtime Network Multiplayer Game
 *   =====================================================
 *   Developed by Group D02 - 2009/2010 Semester 4 - CS2103
 *     Harry Nguyen Duy Hoang <nnduyhoang@yahoo.co.uk>
 *     Kent Chng Siang Rong <fivefootway@gmail.com>
 *     Lim Yong Peng <limpeng1986@gmail.com>
 *     Loh Xiankun <u0807185@nus.edu.sg>
 *   Instructed by
 *     Dr. Damith C.Rajapakse <damith@gmail.com>
 *   =====================================================
 *   $Id: Map.java 598 2010-07-26 17:06:34Z Harry $
 *   $LastChangedDate: 2010-07-26 17:06:34 +0000 (Mon, 26 Jul 2010) $
 *   $LastChangedBy: Harry $
 *--------------------------------------------------------------------------
 */
package battlefield.entity;

import java.io.Serializable;
import java.util.ArrayList;

/**
 * 
 * @author Harry Nguyen
 */
public class Map extends Grid implements Serializable {

    /**
     *
     */
    public static final int WIDTH = 448;
    /**
     *
     */
    public static final int HEIGHT = 448;
    /**
     *
     */
    public static final int ROWS = 14;
    /**
     *
     */
    public static final int COLUMNS = 14;
    private int id;
    private int width;
    private int height;
    private ArrayList<Unit> units;
    private Unit[][] unitGrid;

    /**
     *
     */
    public Map() {
        super();
    }

    /**
     * Construct the Map object with the id, width, height, number rows and columns
     * for the map
     *
     * @param  id  unique id to be allocated to the map
     * @param  width  the number of rows the map will have
     * @param  height  the number of rows the map will have
     * @param  rows  the number of rows the map will have
     * @param  columns  the number of columns the map will have
     */
    public Map(int id, int width, int height, int rows, int columns) {
        super(rows, columns);
        this.id = id;
        unitGrid = new Unit[rows][columns];
        this.width = width;
        this.height = height;
        this.units = new ArrayList<Unit>();
    }

    /**
     * Returns the unique id of the map
     *
     * @return      id of the map
     */
    public int getId() {
        return id;
    }

    /**
     * Returns the width of the map
     *
     * @return      width of the map
     */
    public int getWidth() {
        return width;
    }

    /**
     * Returns the height of the map
     *
     * @return      the height of the map
     */
    public int getHeight() {
        return height;
    }

    /**
     * Returns the list of all unit on map
     *
     * @return      list of all the units on the map
     */
    public ArrayList<Unit> getUnits() {
        return units;
    }

    /**
     * Returns the Unit object at the x and y position
     *
     * @param  x  the x position to get the unit from
     * @param  y  the y position to get the unit from
     * 
     * @return      unit object at the x and y position
     */
    public Unit getUnitAt(int x, int y) {
        if (x < 0 || x >= unitGrid.length) {
            return null;
        }

        if (y < 0 || y >= unitGrid[x].length) {
            return null;
        }

        return unitGrid[x][y];
    }

    /**
     * Sets the number of rows the grid will have
     *
     * @param  x  the x position to place the unit at
     * @param  y  the y position to place the unit at
     * @param  unit  the unit object the place on the map
     *
     * @see Unit
     */
    public void putUnitAt(int x, int y, Unit unit) {
        if (unit != null && x + unit.getRows() <= unitGrid.length && y + unit.getColumns() <= unitGrid[x].length) {
            if (units.contains(unit)) {
                removeUnit(unit);
            }

            unit.setX(x);
            unit.setY(y);

            for (int i = 0; i < unit.getRows(); i++) {
                for (int j = 0; j < unit.getColumns(); j++) {
                    if (unit.hasCellAt(i, j) && super.hasCellAt(x + i, y + j)) {
                        unit.getCellAt(i, j).setBackgroundImage(super.getCellAt(x + i, y + j).getBackgroundImage());
                        unitGrid[x + i][y + j] = unit;
                    }
                }
            }

            units.add(unit);
        }

    }

    /**
     * Removes the unit to remove from the map
     *
     * @param unit
     */
    public void removeUnit(Unit unit) {
        if (units.contains(unit)) {
            for (int i = 0; i < unit.getRows(); i++) {
                for (int j = 0; j < unit.getColumns(); j++) {
                    if (unit.equals(getUnitAt(i + unit.getX(), j + unit.getY()))) {
                        unitGrid[i + unit.getX()][j + unit.getY()] = null;
                    }
                }
            }
            units.remove(unit);
        }
    }

    /**
     * Returns true is there is a unit at the specific x and y position
     *
     * @param x 
     * @param y
     * @return      if there is a unit at specific x and y position
     */
    public boolean hasUnitAt(int x, int y) {
        return getUnitAt(x, y) != null;
    }

    /**
     * Returns Cell object position at the specific x and y position
     *
     * @param  x  the x position of the cell
     * @param  y  the y position of the cell
     * @return      Cell object position at the x and y position
     */
    @Override
    public Cell getCellAt(int x, int y) {
        if (hasUnitAt(x, y)) {
            Unit unit = getUnitAt(x, y);
            if (unit.hasCellAt(x - unit.getX(), y - unit.getY())) {
                return unit.getCellAt(x - unit.getX(), y - unit.getY());
            }
        }

        return super.getCellAt(x, y);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }

        if (!(obj instanceof Map)) {
            return false;
        }

        return ((Map) obj).getId() == this.getId();
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 37 * hash + this.id;
        return hash;
    }
}
